package erequest

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"time"

	"git.edaijia-inc.cn/edaijia/ego/elogger"
	"git.edaijia-inc.cn/edaijia/ego/enaming"
	"git.edaijia-inc.cn/edaijia/ego/etracer"

	"github.com/WJIAN/gorequest"
)

func EEnd(ctx interface{}, req *gorequest.SuperAgent) (resp gorequest.Response, body string, errs []error) {
	etracer.ERequestSpanAround(
		ctx,
		req,
		func() (gorequest.Response, error) {
			resp, body, errs = req.End()

			//handle http code 4xx 5xx
			if resp != nil && resp.StatusCode >= http.StatusBadRequest {
				errs = append(errs, errors.New(fmt.Sprintf("http code error %d,", resp.StatusCode)+body))
			}

			if len(errs) > 0 {
				return resp, errs[0]
			} else {
				return resp, nil
			}
		},
	)

	return
}

func buildServiceUrl(service string, entry string) (string, error) {
	serviceAddr, err := enaming.GetClient(service, "", "")
	if err != nil {
		return "", err
	}

	url := "http://" + serviceAddr
	if len(entry) > 0 && entry[0] == '/' {
		url += entry
	} else {
		url += "/" + entry
	}

	return url, nil
}

/*
 * Get方法请求restful接口,接口返回值必须为json格式
 * 参数: ctx content.Context
 * 		 url 请求地址
 *       params 请求参数,map或者struct,为struct类型时,以json tag作为参数名
 *       result 请求结果json的映射结构,为nil时忽略返回结果
 *       timeout 请求超时时间,单位毫秒
 * 返回值: response golang原生http.Response结构,常用字段StatusCode
 */
func RestGetQuery(ctx interface{}, url string, params interface{}, result interface{}, timeout int) (gorequest.Response, error) {
	erequest := gorequest.New()
	if timeout > 0 {
		erequest.Timeout(time.Duration(timeout) * time.Millisecond)
	}

	req := erequest.Get(url).Query(params)
	var resp gorequest.Response

	resp, body, errs := EEnd(ctx, req)
	if errs != nil {
		elogger.Error("erequest RestGetQuery error", errs[0])
		return resp, errs[0]
	}

	if result != nil {
		err := json.Unmarshal([]byte(body), result)
		if err != nil {
			elogger.Error("erequest RestGetQuery json", err)
			return nil, err
		}
	}

	return resp, nil
}

func RestGetQueryService(ctx interface{}, service string, entry string, params interface{}, result interface{}, timeout int) (gorequest.Response, error) {
	url, err := buildServiceUrl(service, entry)
	if err != nil {
		return nil, err
	}

	return RestGetQuery(ctx, url, params, result, timeout)
}

/*
 * Post方法请求restful接口,接口返回值必须为json格式
 * 参数: url 请求地址
 *       params 请求参数,map或者struct,为struct类型时,以json tag作为参数名
 *       result 请求结果json的映射结构,为nil时忽略返回结果
 *       timeout 请求超时时间,单位毫秒
 * 返回值: response golang原生http.Response结构,常用字段StatusCode
 */
func RestPostQuery(ctx interface{}, url string, params interface{}, result interface{}, timeout int) (gorequest.Response, string, error) {
	erequest := gorequest.New()
	if timeout > 0 {
		erequest.Timeout(time.Duration(timeout) * time.Millisecond)
	}

	req := erequest.Post(url).Query(params)

	resp, body, errs := EEnd(ctx, req)
	if errs != nil {
		elogger.Error("erequest RestGetQuery error", errs[0])
		return resp, "", errs[0]
	}

	if result != nil {
		err := json.Unmarshal([]byte(body), result)
		if err != nil {
			elogger.Error("erequest RestGetQuery json", err)
			return nil, "", err
		}
	}

	return resp, body, nil
}

func RestPostQueryService(ctx interface{}, service string, entry string, params interface{}, result interface{}, timeout int) (gorequest.Response, string, error) {
	url, err := buildServiceUrl(service, entry)
	if err != nil {
		return nil, "", err
	}

	return RestPostQuery(ctx, url, params, result, timeout)
}

/*
 * Post方法请求restful接口,请求body为urlencoded结构,接口返回值必须为json格式
 * 参数: url 请求地址
 *       params 请求参数,map或者struct,为struct类型时,以json tag作为参数名
 *       result 请求结果json的映射结构,为nil时忽略返回结果
 *       timeout 请求超时时间,单位毫秒
 * 返回值: response golang原生http.Response结构,常用字段StatusCode
 */
func RestPostUrlencoded(ctx interface{}, url string, params interface{}, result interface{}, timeout int) (gorequest.Response, string, error) {
	erequest := gorequest.New()
	if timeout > 0 {
		erequest.Timeout(time.Duration(timeout) * time.Millisecond)
	}

	req := erequest.Post(url).Type(gorequest.TypeUrlencoded).Send(params)

	resp, body, errs := EEnd(ctx, req)
	if errs != nil {
		elogger.Error("erequest RestGetQuery error", errs[0])
		return resp, "", errs[0]
	}

	if result != nil {
		err := json.Unmarshal([]byte(body), result)
		if err != nil {
			elogger.Error("erequest RestGetQuery json", err)
			return nil, "", err
		}
	}

	return resp, body, nil
}

/*
 * Post方法请求restful接口,请求body为json结构,接口返回值必须为json格式
 * 参数: url 请求地址
 *       params 请求参数,map或者struct,为struct类型时,以json tag作为参数名
 *       result 请求结果json的映射结构,为nil时忽略返回结果
 *       timeout 请求超时时间,单位毫秒
 * 返回值: response golang原生http.Response结构,常用字段StatusCode
 */
func RestPostJson(ctx interface{}, url string, params interface{}, result interface{}, timeout int) (gorequest.Response, string, error) {
	erequest := gorequest.New()
	if timeout > 0 {
		erequest.Timeout(time.Duration(timeout) * time.Millisecond)
	}

	req := erequest.Post(url).Type(gorequest.TypeJSON).Send(params)

	resp, body, errs := EEnd(ctx, req)
	if errs != nil {
		elogger.Error("erequest RestGetQuery error", errs[0])
		return resp, "", errs[0]
	}

	if result != nil {
		err := json.Unmarshal([]byte(body), result)
		if err != nil {
			elogger.Error("erequest RestGetQuery json", err)
			return nil, "", err
		}
	}

	return resp, body, nil
}

func RestPostJsonService(ctx interface{}, service string, entry string, params interface{}, result interface{}, timeout int) (gorequest.Response, string, error) {
	url, err := buildServiceUrl(service, entry)
	if err != nil {
		return nil, "", err
	}

	return RestPostJson(ctx, url, params, result, timeout)
}
